#include <list>
#include <math.h>
#include <cv.h>
#include <highgui.h>

using namespace std;
enum FeatureType{
	M1=1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16, M17, M18, M19, M20, M21, M22, M23, M24, M25, M26, M27, M28, M29, M30,
	S1, S2, S3, S4, S5, S6, S7, S8, S9, S10,
	C1,C2,C3,C4,C5,C6,C7,C8,
	FrontDinhDauFront,FrontDay,FrontCoTay1,FrontCoTay2,/* truoc*/
	

	/* truoc*/
	FrontCoVai1,FrontCoVai2,FrontDinhVai1,FrontDinhVai2,FrontNach1,FrontNach2,FrontEo1,FrontEo2,FrontCoChan1, FrontCoChan2, FrontMatCaChan1,FrontMatCaChan2,FrontRongChan1, FrontRongChan2,
	FrontMong1,FrontMong2,FrontXuongHong1, FrontXuongHong2,FrontDauGoi1, FrontDauGoi2,FrontBapChan1, FrontBapChan2,FrontTran1, FrontTran2,
	/*Hong^*/
	SideDinhNguc1,SideDinhNguc2,SideMong1, SideMong2,SideDauGoi1,SideDauGoi2,SideBapChan1,SideBapChan2,SideCoChan1, SideCoChan2,SideBanChan1,SideBanChan2,SideXuongHong1, SideXuongHong2,SideDotSongCo,SideDinhDauSide,SideTran1,SideTran2,SideHomCo,SideGotChan,
	SideEo1,SideEo2,
};
struct HSV
{
	int H;
	int S;
	int V;
};
struct Feature
{
	int x;
	int y;
	int nCCValue;
	FeatureType type;
};
class ChainCode
{
public:
	unsigned char nValue;
	int nX;
	int nY;
	ChainCode(){};
	~ChainCode(){};
	ChainCode& operator=(const ChainCode&);
	bool operator==(const ChainCode&);
};

class ImageProcessing
{
public:
	ImageProcessing();
	~ImageProcessing();

private:
	IplImage *pImage;
	IplImage *pImageOri;
	IplImage *pImageGray;
	HSV* pHSV;
	list<ChainCode> lChain;
	list<ChainCode>::iterator iChain;
	list<ChainCode> lTurningPoint;
	int h;
	int w;
	int byteWidth;
public:
	int nCountFeaturePoints;
	Feature features[50];
	int Ymax;
	int Ymin;
	int Xmax;
	int Xmin;
	int nErrorID;	//RGBtoHSV(): 11->20
					//HSVtoRGB(): 21->30
					//FilterOnHSV(..): 31->40
					//MakeCannyEdge():41->50
					//CreateChainCode():51->60
					//ShowFeaturePoint():61->70
public:
	bool LoadImage(char* filename);
	bool RGBtoHSV();
	bool HSVtoRGB();
	bool FilterOnHSV(int Hmin, int Hmax, int Smin, int Smax, int Vmin, int Vmax);
	void SetupGrayImage(unsigned char opt = 0);
	bool MakeCannyEdge();
	bool CreateChainCode();
	bool DetectFeaturePoint(int nType);
	IplImage* GetImageObj();
	IplImage* GetImageOri();
	IplImage* GetImageGrayObj();
	HSV* GetHSV();
	void PaintBackground();
	void GetFeaturesFromSide(ImageProcessing referedObject);
	void GetFeaturesFromFront(ImageProcessing referedObject);
	void DrawFeaturePoints();
	void ExportFeatures( IplImage *img,int type, char* filenamefull, char** fileoutfull);
	char* ErrorReport(int ID);
	
private:
	void Reset();
	void ExtractFeaturesforFront();
	void ExtractFeaturesforSide();
	void DrawMarkerPoint(IplImage *img,int centerX, int centerY,int cellWidth, int cellHeight);
	void ConvertRGBtoHSV(unsigned char r, unsigned char g, unsigned char b, HSV &Output);
	void ConvertHSVtoRGB(HSV in,unsigned char &r,unsigned char &g,unsigned char &b);
	int FindChainCode(int x, int y,int &nextX, int &nextY,unsigned char preValue, unsigned char grayValue);
	void Test_PrintChainCode();
	int GetFeatureHeightFromHead(ImageProcessing ip, FeatureType type);
	void SetFeatureHeightFromHead( FeatureType typeRight,FeatureType typeLeft, int y,int rightMin, int leftMin);
};